package route

import (
	"cowb/log"
	"encoding/json"
	"errors"
	"fmt"
	"reflect"
)

type IClientMsgHandle interface {
	Handle() (code string, data interface{})
}

type Router struct {
	msgMap map[string]reflect.Type
	cmds   []string
}

func NewRouter() *Router {
	r := &Router{}
	r.msgMap = make(map[string]reflect.Type)
	return r
}

func (this *Router) GetCmds() []string {
	return this.cmds
}

func (this *Router) RegistMsg(msg interface{}) {
	msgType := reflect.TypeOf(msg)
	if msgType == nil || msgType.Kind() != reflect.Ptr {
		log.Fatal("json message pointer required")
	}
	msgID := msgType.Elem().Name()
	if _, ok := this.msgMap[msgID]; !ok {
		this.msgMap[msgID] = msgType
		this.cmds = append(this.cmds, msgID)
	}
}

func (this *Router) Handle(cmd string, body []byte) ([]byte, error) {
	if mt, ok := this.msgMap[cmd]; ok {
		msgObj := reflect.New(mt.Elem()).Interface()
		json.Unmarshal(body, msgObj)

		imsg, ok := msgObj.(IClientMsgHandle)
		if ok {
			code, data := imsg.Handle()
			type retMsg struct {
				Cmd  string      `json:"cmd"`
				Code string      `json:"code"`
				Data interface{} `json:"data"`
			}
			ret := retMsg{Cmd: cmd, Code: code, Data: data}
			buf, err := json.Marshal(ret)
			if err != nil {
				log.Error("%v", err)
			}
			return buf, err
		}
	}
	return nil, errors.New(fmt.Sprintf("没有匹配到cmd:%s", cmd))
}
